package com.shopcart.pay.ali;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;

/* *
 *类名：AlipayNotify
 *功能：支付宝通知处理类
 *详细：处理支付宝各接口通知返回
 *版本：3.3
 *日期：2012-08-17
 *说明：
 *以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用，只是提供一个参考

 *************************注意*************************
 *调试通知返回时，可查看或改写log日志的写入TXT里的数据，来检查通知返回是否正常
 */
public class AlipayNotify {

    /**
     * 支付宝消息验证地址
     */
    private static final String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";
    
    /**
     * 验证消息是否是支付宝发出的合法消息，验证callback
     * @param params 通知返回来的参数数组
     * @return 验证结果
     */
    public static boolean verifyReturn(Map<String, String> params,String payKey) {
	    String sign = "";
	    //获取返回时的签名验证结果
	    if(params.get("sign") != null) {sign = params.get("sign");}
	    //验证签名
	    boolean isSign = getSignVeryfy(params, sign, true,payKey);

        //写日志记录（若要调试，请取消下面两行注释）
        String sWord = "isSign=" + isSign + "\n 返回回来的参数：" + AlipayCore.createLinkString(params);
	    AlipayCore.logResult(sWord);

        //判断isSign是否为true
        //isSign不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
        if (isSign) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 验证消息是否是支付宝发出的合法消息，验证服务器异步通知
     * @param params 通知返回来的参数数组
     * @return 验证结果
     */
    public static boolean verifyNotify(Map<String, String> params,String payKey,String partner) throws Exception {
    	//获取是否是支付宝服务器发来的请求的验证结果
    	String responseTxt = "true";
    	try {
        	//XML解析notify_data数据，获取notify_id
	    	Document document = DocumentHelper.parseText(params.get("notify_data"));
	    	String notify_id = document.selectSingleNode( "//notify/notify_id" ).getText();
			responseTxt = verifyResponse(notify_id,partner);
    	} catch(Exception e) {
    		responseTxt = e.toString();
    	}
    	
    	//获取返回时的签名验证结果
	    String sign = "";
	    if(params.get("sign") != null) {sign = params.get("sign");}
	    boolean isSign = getSignVeryfy(params, sign,false,payKey);

        //写日志记录（若要调试，请取消下面两行注释）
	    String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign + "\n sign="+sign+"\n  返回回来的参数：" + AlipayCore.createLinkStringNoSort(params);
	    AlipayCore.logResult(sWord);

        //判断responsetTxt是否为true，isSign是否为true
        //responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
        //isSign不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
        if (isSign && responseTxt.equals("true")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据反馈回来的信息，生成签名结果
     * @param Params 通知返回来的参数数组
     * @param sign 比对的签名结果
     * @param isSort 是否排序
     * @return 生成的签名结果
     */
	private static boolean getSignVeryfy(Map<String, String> Params, String sign, boolean isSort,String payKey) {
    	//过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = AlipayCore.paraFilter(Params);
        //获取待签名字符串
    	String preSignStr = "";
    	if(isSort) {
    		preSignStr = AlipayCore.createLinkString(sParaNew);
    	} else {
    		preSignStr = AlipayCore.createLinkStringNoSort(sParaNew);
    	}
        //获得签名验证结果
        boolean isSign = false;
    	isSign = MD5.verify(preSignStr, sign,payKey, "utf-8");
        return isSign;
    }
	
	public static void main(String[] args) {
		String n = "body=订单号：140513091151734&buyer_email=576462028@qq.com&buyer_id=2088202631744809&discount=0.00&gmt_close=2014-05-26 16:54:37&gmt_create=2014-05-26 16:54:36&gmt_payment=2014-05-26 16:54:37&is_total_fee_adjust=N&notify_id=dc32b8abb7bc58c705d22cdc11380d5f6g&notify_time=2014-05-26 16:54:37&notify_type=trade_status_sync&out_trade_no=8b9d2127-da3b-11e3-9fc1-74d4357db269&payment_type=1&price=0.01&quantity=1&seller_email=udowscrmadmin@163.com&seller_id=2088111040781043&subject=订单号：140513091151734&total_fee=0.01&trade_no=2014052639560280&trade_status=TRADE_FINISHED&use_coupon=N";
		String sign = "hynGdKyIrKqTUwFy986A7KIydbDvWvB2VzDDtQ7qWC7U3p7n7lav3J13QosFgzKarxxcPu+c5WlNfkZw94m7Ik2uFPmojrJ5C+F7lfzD4JFxKLQ4Xht8CjOhdnBFHlSc3LuQlNPGUrQ/w8oDNDFVJO8h9VbHqhrn2w+uctk749E=";
		String key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpWYDVbBsdgL43h9cO/qjWA8d94XPCPTQM7vCGj11qtaCp8vRbTIaZSK3VqTLEmcES8jWfSz7oViB0IpupgwzRhGp0aQAvBIkAqCNYY2KXr1ssq7OY0v+bRK9zMWhLtI7YbLWIChtVlNs4s5pXmy9IKVYrBsjQ6XAl6JspDytZvQIDAQAB";
		System.out.println(RSA.verify(n, sign, key, "utf-8"));
	}

    /**
    * 获取远程服务器ATN结果,验证返回URL
    * @param notify_id 通知校验ID
    * @return 服务器ATN结果
    * 验证结果集：
    * invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空 
    * true 返回正确信息
    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
    */
    private static String verifyResponse(String notify_id,String partner) {
        //获取远程服务器ATN结果，验证是否是支付宝服务器发来的请求
        String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;
        return checkUrl(veryfy_url);
    }
    
    /**
    * 获取远程服务器ATN结果
    * @param urlvalue 指定URL路径地址
    * @return 服务器ATN结果
    * 验证结果集：
    * invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空 
    * true 返回正确信息
    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
    */
    private static String checkUrl(String urlvalue) {
        String inputLine = "";

        try {
            URL url = new URL(urlvalue);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection
                .getInputStream()));
            inputLine = in.readLine().toString();
        } catch (Exception e) {
            e.printStackTrace();
            inputLine = "";
        }

        return inputLine;
    }

	public static boolean verifyMobileNotify(Map<String, String> params, String payKey) {
		String sign = "";
	    //获取返回时的签名验证结果
	    if(params.get("sign") != null) {sign = params.get("sign");}
	    //验证签名
	    //过滤空值、sign与sign_type参数
    	Map<String, String> sParaNew = AlipayCore.paraFilter(params);
        //获取待签名字符串
    	String preSignStr = AlipayCore.createLinkString(sParaNew);
        //获得签名验证结果
		boolean isSign = false;
		isSign = RSA.verify(preSignStr, sign, payKey, "utf-8");
        if (isSign) {
            return true;
        } else {
        	String sWord = "isSign=" + isSign + "\n 返回回来的参数：" + preSignStr;
    	    AlipayCore.logResult(sWord);
            return false;
        }
	}
}
